package com.xtkj.superclub_information.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xtkj.commons.JsonParse;
import com.xtkj.commons.JsonResult;
import com.xtkj.commons.SnowflakeIdWorker;
import com.xtkj.superclub_entity.entity.travel.*;
import com.xtkj.superclub_entity.entity.user.User;
import com.xtkj.superclub_information.client.IPhotoClient;
import com.xtkj.superclub_information.client.IUploadClient;
import com.xtkj.superclub_information.client.IUserClient;
import com.xtkj.superclub_information.dao.*;
import com.xtkj.superclub_information.service.ITravelService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

/**
 * @author lizheqi
 * @create 2020-01-02-10:27
 */
@Service
public class TravelServiceImpl implements ITravelService {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private IUploadClient uploadClient;
    /**
     *根据最新评论来进行排序
     */
    @Autowired
    private TravelDao travelDao;
    @Autowired
    private TravelCommentDao travelCommentDao;
    @Autowired
    private TravelPraiseDao travelPraiseDao;
    @Autowired
    private IUserClient userClient;
    @Autowired
    private TravelCommentReplyDao travelCommentReplyDao;
    @Autowired
    private TravelTypeDao travelTypeDao;
    @Autowired
    private TravelPhotosDao travelPhotosDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IPhotoClient photoClient;
    /**
     * 根据更新日期来进行排序
     * @return
     */
    @Override
    public List<Travel> getTravelsListByNews() {
        QueryWrapper<Travel> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("updatedtm");
        List<Travel> travels = travelDao.selectList(wrapper);
        return updateTravel(travels);
    }

    /**
     * 根据创建日期来进行排序
     * @return
     */
    @Override
    public List<Travel> getTravelsListByTime() {
        QueryWrapper<Travel> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("createdtm");
        List<Travel> travels = travelDao.selectList(wrapper);
        return updateTravel(travels);
    }

    /**
     * 获取热门游记列表
     * @return
     */
    @Override
    public List<Travel> getTravelsListByHot() {
        QueryWrapper<Travel> wrapper = new QueryWrapper<>();
        //获取游记列表
        List<Travel> travels = travelDao.selectList(wrapper);
        //热门游记算法评论权重比为7，浏览权重比为 3，新发布游记和新活动一样时间算法一样
        for (int i=0;i<travels.size();i++){
            int minIndex = i;
            for(int j=0;j<travels.size();j++){
                if(getTravelCommentCountByTravelId(travels.get(j).getTravelId())*0.7+travels.get(j).getReadNum()*0.3< getTravelCommentCountByTravelId(travels.get(i).getTravelId())*0.7+travels.get(i).getReadNum()*0.3){
                    minIndex = j;//将最小数的索引保存
                }
            }
            Travel travel = travels.get(i);
            Travel tempTravel = travels.get(minIndex);
            travels.set(i,tempTravel);
            travels.set(minIndex,travel);
        }
        return updateTravel(travels);
    }

    /**
     * 获取游记详情
     * @return
     */
    @Override
    public Map<String,Object> getTravelsInfo(Travel travel,String userId) {
        HashOperations ops = redisTemplate.opsForHash();
        Map reads = ops.entries("read");
        int readNum = 0;
        //如果redis里面没有数据则会从数据库里面查找
        Iterator iterator = reads.keySet().iterator();
        while (iterator.hasNext()){
            String travelId = iterator.next().toString();
            if(travelId.equals(travel.getTravelId())){
                //对其阅读数加一
                readNum = Integer.valueOf(ops.get("read", travelId).toString())+1;
                ops.put("read",travelId,readNum);
            }
        }
        Map<String,Object> map = new HashMap<>();
        //根据游记编号获取该游记信息
        QueryWrapper<Travel> travelWrapper = new QueryWrapper<>();
        travelWrapper.eq("travel_id",travel.getTravelId());
        Travel dbTravel = travelDao.selectOne(travelWrapper);
        dbTravel.setReadNum(readNum);

        //获取游记类型
        QueryWrapper<TravelType> typeWrapper = new QueryWrapper<>();
        typeWrapper.eq("travel_type_id",dbTravel.getTravelTypeId());
        TravelType travelType = travelTypeDao.selectOne(typeWrapper);
        dbTravel.setTravelType(travelType);
        map.put("travel",dbTravel);

        //获取该游记的点赞数量,直接从redis里面获取
        Integer praiseNum = 0;
        if(ops.size(travel.getTravelId())!=null){
            praiseNum = Integer.valueOf(ops.size(travel.getTravelId()).toString());
        }else{
            QueryWrapper<TravelPraise> praiseWrapper = new QueryWrapper<>();
            praiseWrapper.eq("travel_id",travel.getTravelId());
            praiseNum = travelPraiseDao.selectCount(praiseWrapper);
        }
        map.put("praiseNum",praiseNum);

        //获取改游记的点赞人的编号集合,点赞人的信息不需要显示
        Map entries = ops.entries(travel.getTravelId());
        iterator = entries.keySet().iterator();
        List<User> userList = new ArrayList<>();
        while (iterator.hasNext()){
            String redisUserId =  iterator.next().toString();
            JsonResult json = userClient.getUser(new User().setUserId(redisUserId));
            userList.add(JsonParse.string2Obj(json.getData().toString(), User.class));
        }
        map.put("userList",userList);

        //获取该游记的评论数量
        QueryWrapper<TravelComment> commentWrapper = new QueryWrapper<>();
        commentWrapper.eq("travel_id",travel.getTravelId());
        int commentNum = travelCommentDao.selectCount(commentWrapper);
        map.put("commentNum",commentNum);

        //获取改游记对应的评论信息，需要进一步封装评论人的信息
        List<TravelComment> travelComments = travelCommentDao.selectList(commentWrapper);
        for(TravelComment travelComment:travelComments){
            //需要根据用户编号查询该用户信息
            JsonResult json = userClient.getUser(new User().setUserId(travelComment.getUserId()));
            User user = JsonParse.string2Obj(json.getData().toString(),User.class);
            travelComment.setUser(user);
            //每条评论表里面带有各项评论回复信息
            QueryWrapper<TravelCommentReply> replyWrapper = new QueryWrapper<>();
            replyWrapper.eq("travel_comment_id",travelComment.getTravelCommentId());
            List<TravelCommentReply> travelCommentReplies = travelCommentReplyDao.selectList(replyWrapper);
            for(TravelCommentReply travelCommentReply:travelCommentReplies){
                JsonResult jsonResult = userClient.getUser(new User().setUserId(travelComment.getUserId()));
                User replyUser = JsonParse.string2Obj(jsonResult.getData().toString(),User.class);
                travelCommentReply.setUser(replyUser);
            }
        }
        map.put("travelComments",travelComments);
        //根据游记编号获取游记照片
        QueryWrapper<TravelPhotos> photosWrapper = new QueryWrapper<>();
        photosWrapper.eq("travel_id",travel.getTravelId());
        List<TravelPhotos> travelPhotos = travelPhotosDao.selectList(photosWrapper);
        map.put("travelPhotos",travelPhotos);
        return map;
    }

    /**
     * 游记投稿功能
     * @param travel
     */
    @Override
    public void travelsContribute(Travel travel) {
        //先通过雪花生成游记编号
        String travelId = snowflakeIdWorker.nextId()+"";
        travel.setTravelId(travelId);
        //获取游记内容,并从游记内容里面提取图片的地址
        String travelContent = travel.getTravelContent();
        List<String> photoList = new ArrayList<>();
        //解析成dom
        Document doc = Jsoup.parse(travelContent);
        Elements elements = doc.select("[src]");
        //拿到src里面的地址
        for(Element element:elements){
            photoList.add(element.attr("src"));
        }
        System.out.println(photoList);
        //判断封面有没有
        if(travel.getTravelFace()==null){
            travel.setTravelFace(photoList.get(0));//以第一张照片地址作为游记封面
        }
        travel.setCreatedtm(new Date()).setUpdatedtm(new Date());
        //对游记表进行增加
        travelDao.insert(travel);
        //对游记照片表进行增加
        for(String travelPhoto:photoList){
            //获取每个照片的地址，并通过雪花生成对应的游记照片编号
            String travelPhotoId =  snowflakeIdWorker.nextId()+"";
            TravelPhotos photo = new TravelPhotos().setTravelId(travel.getTravelId()).setTravelPhoto(travelPhoto).setTravelPhotoId(travelPhotoId).setCreatedtm(new Date()).setUpdatedtm(new Date());
            //插入游记照片表
            travelPhotosDao.insert(photo);
            System.out.println(11);
        }
        //获取游记发布人的信息
        JsonResult userResult = userClient.getUser(new User().setUserId(travel.getUserId()));
        User user = JsonParse.string2Obj(userResult.getData().toString(), User.class);
        //完成后将照片存放到个人相册的游记相册中
        String albumId = photoClient.getAlbumId(user.getPersonalAlbumId()).getData().toString();
        Map<String, Object> map = new HashMap<>();
        map.put("mAlbumId",albumId);
        map.put("mPhotoUrl",photoList);
        map.put("mType","personal");
        photoClient.addPhotoToAlBum(map);
    }


    /**
     * 上传照片
     * @param file
     */
    @Override
    public String uploadPhoto(MultipartFile file) {
        String address = uploadClient.contextLoads(file);
        return address;
    }


    /**
     * 根据游记编号获取该游记所有的评论数量
     * @return
     */
    public int getTravelCommentCountByTravelId(String travelId){
        QueryWrapper<TravelComment> wrapper = new QueryWrapper<>();
        wrapper.eq("travel_id",travelId);
        return travelCommentDao.selectCount(wrapper);
    }


    /**
     * 获取游记列表时从redis获取阅读数并更新游记
     */
    public List<Travel> updateTravel(List<Travel> travels){
        HashOperations ops = redisTemplate.opsForHash();
        //显示游记时会显示该游记的阅读数
        for (Travel travel:travels){
            if(ops.get("read",travel.getTeamId())!=null) {
                //从redis里面获取阅读数
                int readNum = Integer.valueOf(ops.get("read", travel.getTravelId()).toString());
                travel.setReadNum(readNum);
            }
        }
        return travels;
    }

}
